package com.example.apiproxydemo.core.代理客户端;

import io.netty.channel.ChannelOption;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.timeout.WriteTimeoutHandler;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.reactive.function.client.ExchangeStrategies;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.http.client.HttpClient;
import reactor.netty.tcp.TcpClient;

import javax.net.ssl.SSLException;
import java.util.concurrent.TimeUnit;

/**
 * @Description HTTP 代理客户端
 * @Author zhoupan
 * @Date 2022/2/25 13:49
 */
@Service
@RequiredArgsConstructor
public class HttpProxytClient {
//    final private WebClient  webClient;
    @Value("${demo.connReadTimeout:10000}")
    private Long connReadTimeout;

    @Value("${demo.connWriteTimeout:10000}")
    private Long connWriteTimeout;

    @Value("${demo.chConnTimeout:10000}")
    private Integer chConnTimeout;
    @Value("${demo.chTcpNodelay:false}")
    private Boolean chTcpNodelay;

    @Value("${demo.chSoKeepAlive:false}")
    private Boolean chSoKeepAlive;
    private Boolean       compress =null;

    private Boolean       trustInsecureSSL        = null; // false

    @Bean("webClient")
    public WebClient webClient() {

        HttpClient httpClient = HttpClient.create()
                .tcpConfiguration(
                        tcpClient -> {
                            TcpClient newTcpClient = tcpClient.doOnConnected(
                                    connection -> {
                                        if (connReadTimeout != null) {
                                            connection.addHandlerLast(new ReadTimeoutHandler(connReadTimeout,   TimeUnit.MILLISECONDS));
                                        }
                                        if (connWriteTimeout != null) {
                                            connection.addHandlerLast(new WriteTimeoutHandler(connWriteTimeout, TimeUnit.MILLISECONDS));
                                        }
                                    }
                            );
                            if (chConnTimeout != null) {
                                newTcpClient = newTcpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, chConnTimeout);
                            }
                            if (chTcpNodelay != null) {
                                newTcpClient = newTcpClient.option(ChannelOption.TCP_NODELAY,            chTcpNodelay);
                            }
                            if (chSoKeepAlive != null) {
                                newTcpClient = newTcpClient.option(ChannelOption.SO_KEEPALIVE,           chSoKeepAlive);
                            }
                            return newTcpClient;
                        }
                );

        if (compress != null) {
            httpClient = httpClient.compress(compress);
        }
        /*
        if (responseTimeout != null) {
            httpClient = httpClient.responseTimeout(Duration.ofMillis(responseTimeout));
        }
        */

        if (trustInsecureSSL != null && trustInsecureSSL) {
            try {
                SslContext sslContext = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();
                httpClient = httpClient.secure(spec -> spec.sslContext(sslContext));

            } catch (SSLException e) {
                throw new RuntimeException(e);
            }
        }

        return  WebClient.builder()
                .exchangeStrategies(
                        ExchangeStrategies.builder().codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(-1))
                                .build()
                )
                .clientConnector(new ReactorClientHttpConnector(httpClient))
                .build();
    }





}
